<?php
namespace app\admin\service;

use app\Exception;
use app\admin\model\AdminUser;
use app\admin\model\Role;
use think\Validate;

class RoleManger
{
    function find($id)
    {
        $query = Role::getQuery();
        return $query->where($query->getPk(),'=',$id)->find();
    }

    function all()
    {
        return Role::select();
    }

    function insert($data)
    {
        $data = array_only($data,['title','rules','desc']);
        $va = new Validate;
        $va->rule([
            'title'=>'require',
            'rules'=>'require|array|r1:'
        ])->extend('r1',function($values){
            foreach($values as $value){
                if($this->convertRule($value) === null){
                    return "rule 验证错误";
                }
            }
            return true;
        });
        if(!$va->check($data)){
            throw new Exception($va->getError());
        }
        if(isset($data['rules']) && $data['rules'] != ''){
            $data['rules'] = array_values($data['rules']);
            $data['rules'] = json_encode($data['rules']);
        }else{
            $data['rules'] = '[]';
        }
        Role::create($data);
        return true;
    }

    function delete($id){
        if(count($this->getUsers($id)) > 0){
            throw new \app\Exception("该角色下还有id无法更新");
        }
        $pk = Role::getQuery()->getPk();
        return Role::getQuery()->where($pk,$id)->delete();
    }


    function getUsers($id){
        return AdminUser::getQuery()->where('role_id',$id)->select();
    }

    function update($id,$data)
    {
        $pk = Role::getQuery()->getPk();
        /** @var Role */
        $role = Role::getQuery()->where($pk,'=',$id)->find();
        if(!$role){
            throw new \app\Exception("找不到该用户组");
        }
        $va = new Validate;
        $va->rule([
            'rules'=>'array|r1:'
        ])->extend('r1',function($values){
            foreach($values as $value){
                if(null === $rules = $this->convertRule($value)){
                    return "rule 验证错误";
                }
            }
            return true;
        });
        if(!$va->check($data)){
            throw new \app\Exception($va->getError());
        }
        if(isset($data['rules'])){
            $data['rules'] = array_values($data['rules']);
            $data['rules'] = json_encode($data['rules']);
        }
        return Role::getQuery()->where($pk,'=',$id)->update($data) > 0;
    }

    /**
     * 将规则字符串转换为规则对象
     * @param string $rule
     */
    function convertRule($rule)
    {
        $tokens =  explode('/',$rule);
        $rules = [

        ];
        foreach($tokens as $key=>$token){
            if(strlen($token) < 1){
                return null;
            }
            switch($token[0]){
                case '*':
                    if($token == '**'){
                        if($key !== count($tokens) -1){
                            return null;
                        }else{
                            $rules[] = [
                                'type'=>'**',
                                'value'=>'**'
                            ];
                        }
                    }else{
                        $rules[] = [
                            'type'=>'*',
                            'value'=>'*'
                        ];
                    }
                    break;
                case '[':
                    $values = [];
                    if(preg_match('/^\[([^\]]+)\]$/',trim($token),$match)){
                        $values = array_map(function($item){
                            return trim($item);
                        },explode(',',$match[1]));
                    }else{
                        return null;
                    }
                    $rules[] = [
                        'type'=>'enum',
                        'value'=>$values
                    ];
                    break;
                case '{':
                    $values = [];
                    if(preg_match('/^\{(\s*\d+\s*\,\s*\d+\s*)\}$/',trim($token),$match)){
                        $values = array_map(function($item){
                            return (int)trim($item);
                        },explode(',',$match[1]));
                    }else{
                        return null;
                    }
                    if($values[0] >= $values[1]){
                        return null;
                    }
                    $rules[] = [
                        'type'=>'between',
                        'value'=>$values
                    ];
                    break;
                case '$':
                    $rules[] = [
                        'type'=>'$',
                        'value'=>'$'
                    ];
                    break;
                default:
                    if(preg_match('/^[A-Za-z0-9_\-]+$/',trim($token),$match)){
                        $rules[] = [
                            'type'=>'const',
                            'value'=>$token
                        ];
                    }else{
                        return null;
                    }
            }
        }
        return new Rule($rules);
    }
    function verifyRule($rule)
    {
        return $this->convertRule($rule) !== null;
    }

    function buildRule($rules)
    {
        $tokens = [];
        foreach($rules as $rule){
            switch($rule['type']){
                case 'enum':
                    $value = implode(',',$rule['value']);
                    $tokens[] = '{'.$value.'}';
                    break;
                case 'between':
                    $value = implode(',',$rule['value']);
                    $tokens[] = '['.$value.']';
                    break;
                default:
                    $token[] = $rule['value'];
            }
        }
        return explode('/',$tokens);
    }
}